package com.sicent.operate.common.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.ResourceBundle;
import java.util.Set;

import org.apache.commons.lang.StringUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

/** 
 * @author:zhaoyinchuan
 *
 * @version:1
 *
 * @Create:2014年7月29日 上午9:27:12 
 */
public class MiddlewareUtil {
	
	private final static String PREFIX = "sicent";
	private final static String ENCODE = "UTF-8";
	private static ResourceBundle bundle;
	private static String host;
	private static Integer port;
	
	static{
		bundle = ResourceBundle.getBundle("config");
		host = bundle.getString("middleware.ip");
		port = Integer.valueOf(bundle.getString("middleware.port"));
		//host="10.34.52.44";
		//host= "10.34.39.133";
		//port=8001;
	}
	
	public static String sendMessage4String(String cmd, String serviceName, Map<String,Object> bodyMap)throws Exception{
		String message = null;
		try {
			message = getMessage(cmd, serviceName, bodyMap);
		} catch (UnsupportedEncodingException e1) {
			e1.printStackTrace();
		}
		MessageSt messageSt = new MessageSt();
		try {
			sendReceiveMessage(message, messageSt);
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return parseMsgBodyString(messageSt);
	}
	/*
	 * 发送消息并解析返回结果
	 */
	public static JSONArray sendMessage4Array(String cmd, String serviceName, Map<String,Object> bodyMap)throws Exception{
		String message = null;
		try {
			message = getMessage(cmd, serviceName, bodyMap);
		} catch (UnsupportedEncodingException e1) {
			e1.printStackTrace();
		}
		MessageSt messageSt = new MessageSt();
		try {
			sendReceiveMessage(message, messageSt);
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		JSONArray array = parseMsgBodyArray(messageSt);
		return formatArray(array);
	}
	
	/*
	 * 发送消息并解析返回结果
	 */
	public static <T> List<T> sendMessage4List(String cmd, String serviceName, Map<String,Object> bodyMap, Class<T> c)throws Exception{
		JSONArray array = sendMessage4Array(cmd, serviceName, bodyMap);
		List<T> list = new ArrayList<T>();
		for(int i=0; i<array.size(); i++){
			list.add(array.getObject(i, c));
		}
		return list;
	}
	
	public static <T> T sendMessage4Object(String cmd, String serviceName, Map<String,Object> bodyMap, Class<T> c) throws Exception{
		JSONArray array = sendMessage4Array(cmd, serviceName, bodyMap);
		if (array.size() > 0) {
			return array.getObject(0, c);
		}
		return null;
	}
	
	public static Boolean sendMessage4Boolean(String cmd, String serviceName, Map<String,Object> bodyMap)throws Exception{
		String message = null;
		try {
			message = getMessage(cmd, serviceName, bodyMap);
			System.out.println("********sendMessage4Boolean--cmd:"+cmd+",serviceName:"+serviceName+",bodyMap:"+JSON.toJSONString(bodyMap, false)+",message:"+message);
		} catch (UnsupportedEncodingException e1) {
			e1.printStackTrace();
		}
		MessageSt messageSt = new MessageSt();
		try {
			sendReceiveMessage(message, messageSt);
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return parseMsgBodyBoolean(messageSt);
	}
	
	private static void sendReceiveMessage(String message, MessageSt messageSt) throws Exception{
		/*Socket client = new Socket(host, port);
		client.setSoTimeout(5*1000);*/
		Socket client = new Socket();
		client.setSoTimeout(30*1000);
		client.setReuseAddress(true);
		client.connect(new InetSocketAddress(host, port));
		client.setSoLinger(true, 0); 
		BufferedInputStream inputStream = null;
		BufferedOutputStream outputStream = null;
		try{
			//发送消息命令
			outputStream = new BufferedOutputStream(client.getOutputStream());
			outputStream.write(message.getBytes(ENCODE));
			outputStream.flush();
			//接收返回结果
			inputStream = new BufferedInputStream(client.getInputStream());
			receiveAndParseMsg(inputStream, messageSt);
		}catch(Exception e){
			e.printStackTrace();
//			throw e;
		}finally{
			inputStream.close();
			outputStream.close();
			client.close();
		}
		if(!checkMsgValid(messageSt)){
			throw new SocketException("format of returned message is not valid."+messageSt.toString());
		}
	}
	
	//检查消息格式正确性
	private static boolean checkMsgValid(MessageSt message){
		if(PREFIX.equals(message.getPrefix())){
			String headerContent = message.getHeaderContent();
			String bodyContent = message.getBodyContent();
			if(headerContent.startsWith("{")&&headerContent.endsWith("}")){
				if(bodyContent.startsWith("{")&&bodyContent.endsWith("}")){
					return true;
				}
			}
		}
		return false;
	}
	
	/*
	 * 接收并解析返回的消息
	 * 协议格式：sicent+6位总长度+6位header长度+header+6位body长度+body
	 */
	private static void receiveAndParseMsg(BufferedInputStream inputStream, MessageSt messageSt) throws NumberFormatException, IOException{
		//读取前12个字节
		byte[] fixBytes = new byte[12];
		inputStream.read(fixBytes, 0, 12);
		if(PREFIX.equals(convertToString(Arrays.copyOfRange(fixBytes, 0, 6)))){
			messageSt.setPrefix(PREFIX);
		}else{
			throw new SocketException("protocol must start with sicent.");
		}
		messageSt.setTotalLen(convertToString(Arrays.copyOfRange(fixBytes, 6, 12)));
		//读取消息内容
		int length = Integer.parseInt(messageSt.getTotalLen(), 16);
		byte[] varBytes = new byte[length];
		inputStream.read(varBytes, 0, length);
		//解析消息内容
		messageSt.setHeaderLen(convertToString(Arrays.copyOfRange(varBytes, 0, 6)));
		length = Integer.parseInt(messageSt.getHeaderLen(), 16);
		messageSt.setHeaderContent(convertToString(Arrays.copyOfRange(varBytes, 6, 6+length)));
		messageSt.setBodyLen(convertToString(Arrays.copyOfRange(varBytes, 6+length, 12+length)));
		messageSt.setBodyContent(convertToString(Arrays.copyOfRange(varBytes, 12+length, varBytes.length)));
	}
	
	//字节集合转换字符串
	private static String convertToString(byte[] bytes) throws UnsupportedEncodingException{
		return new String(bytes, ENCODE).trim();
	}
	
	/*
	 * 组装发送的消息
	 * 协议格式：sicent+6位总长度+6位header长度+header+6位body长度+body
	 */
	private static String getMessage(String cmd, String serviceName, Map<String,Object> bodyMap) throws Exception{
		String header = "{\"service\":\""+serviceName+"\",\"cmd\":\""+cmd+"\",\"type\":1}";
		String body = bodyMap==null?"{}":new JSONObject(bodyMap).toJSONString();
		int headerSize = header.getBytes(ENCODE).length;
		int bodySize = body.getBytes(ENCODE).length;
		String headerLen = Integer.toHexString(headerSize);
		String bodyLen = Integer.toHexString(bodySize);
		String totalLen = Integer.toHexString(headerSize+bodySize+12);
		return PREFIX+formatHexString(totalLen)
				+formatHexString(headerLen)+header
				+formatHexString(bodyLen)+body;
	}
	
	private static String formatHexString(String hexStr)throws SocketException{
		int length = hexStr.length();
		StringBuilder sb = new StringBuilder(hexStr);
		if(length > 6){
			 throw new SocketException("length mustn't be longer than six.");
		}else{
			for(int i=0; i<6-length; i++){
				sb.insert(0, '0');
			}
		}
		return sb.toString();
	}
	
	private static String parseMsgBodyString(MessageSt messageSt)throws SocketException{
		if(messageSt != null){
			System.out.println("*****parseMsgBodyString:"+JSON.toJSONString(messageSt, false));
			String bodyMsg = messageSt.getBodyContent();
			System.out.println(bodyMsg);
			if(StringUtils.isNotEmpty(bodyMsg)){
				JSONObject bodyObj = JSON.parseObject(bodyMsg);
				String resFlag = bodyObj.getString("result");
				if(resFlag.equals("ok")){
					return bodyObj.getString("result_data");
				}else if(resFlag.equals("error") || resFlag.equals("timeout")){
					throw new SocketException("result error:"+bodyObj.getString("result_data"));
				}
			}
		}
		return "";
	}
	
	//解析body返回结果
	private static JSONArray parseMsgBodyArray(MessageSt messageSt)throws SocketException{
		if(messageSt != null){
			System.out.println("*****parseMsgBodyArray:"+JSON.toJSONString(messageSt, false));
			String bodyMsg = messageSt.getBodyContent();
			if(StringUtils.isNotEmpty(bodyMsg)){
				JSONObject bodyObj = JSON.parseObject(bodyMsg);
				String resFlag = bodyObj.getString("result");
				if(resFlag.equals("ok")){
					return JSON.parseArray(bodyObj.getString("result_data"));
				}else if(resFlag.equals("error") || resFlag.equals("timeout")){
					throw new SocketException("result error:"+bodyMsg);
				}
			}
		}
		return new JSONArray();
	}
	
	private static Boolean parseMsgBodyBoolean(MessageSt messageSt)throws SocketException{
		if(messageSt != null){
			String bodyMsg = messageSt.getBodyContent();
			System.out.println("*****parseMsgBodyBoolean:"+JSON.toJSONString(messageSt, false));
			if(StringUtils.isNotEmpty(bodyMsg)){
				JSONObject bodyObj = JSON.parseObject(bodyMsg);
				String resFlag = bodyObj.getString("result");
				if(resFlag.equals("ok")){
					return true;
				}else if(resFlag.equals("error") || resFlag.equals("timeout")){
					throw new SocketException("result error:"+bodyMsg);
				}
			}
		}
		return false;
	}
	
	//格式化result_data的key值，以便前端模板使用
	private static JSONArray formatArray(JSONArray bodyArr){
		HashMap<String,String> rowMap = new HashMap<String,String>();
		JSONArray returnArr = new JSONArray();
		if(bodyArr != null && bodyArr.size() > 0){
			Set<String> keys = bodyArr.getJSONObject(0).keySet();
			Iterator<String> keyIter = keys.iterator();
			while(keyIter.hasNext()){
				String key = (String) keyIter.next();
				String newKey = formatKeyName(key);
				rowMap.put(key, newKey);
			}
			for(int i=0; i<bodyArr.size(); i++){
				Iterator<Entry<String,Object>> iter = bodyArr.getJSONObject(i).entrySet().iterator();
				JSONObject newObj = new JSONObject();
				while(iter.hasNext()){
					Entry<String, Object> entry = iter.next();
					String key = (String) entry.getKey();
					Object value = entry.getValue();
					newObj.put(rowMap.get(key), value);
				}
				returnArr.add(newObj);
			}
		}
		return returnArr;
	}
	
	//key值下划线转换成驼峰结构
	private static String formatKeyName(String name) {
		StringBuilder result = new StringBuilder();
		if (name != null && name.length() > 0) {
			result.append(name.substring(0, 1).toLowerCase());
			for (int i = 1; i < name.length(); i++) {
				String currentStr = name.substring(i, i + 1);
				String preStr = name.substring(i-1, i);
				if(currentStr.equals("_")){
					continue;
				}else if(preStr.equals("_")) {
					result.append(currentStr.toUpperCase());
				}else {
					result.append(currentStr);
				}
			}
		}
		return result.toString();
	}
	
	private static boolean sendClearCmd4Boolean(String cmd , Map<String,Object> bodyMap ){
		try {
			boolean flag =  MiddlewareUtil.sendMessage4Boolean(cmd, "APP_0013", bodyMap);
			System.out.println(">>>>>>>>>>>>>clearCacheDataBySnbid:cmd->"+cmd+",bodyMap->"+bodyMap+",result->"+flag);
			return flag;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}
	
	public static boolean clearCacheDataBySnbid(String cmd , String snbid){
		if(StringUtils.isBlank(cmd) || StringUtils.isBlank(snbid)){
			return false;
		}
		Map<String,Object> bodyMap = new HashMap<String, Object>();
		bodyMap.put("snbid", snbid.trim());
		return sendClearCmd4Boolean(cmd, bodyMap);
	}
	
	
	
	public static boolean clearCacheDataByBarId(String cmd , Integer barId){
		if(StringUtils.isBlank(cmd) || barId==null){
			return false;
		}
		Map<String,Object> bodyMap = new HashMap<String, Object>();
		bodyMap.put("barId", barId);
		return sendClearCmd4Boolean(cmd, bodyMap);
	}
	
	public static boolean clearCacheDataByColumn(String cmd , String idColumn , Integer value){
		if(StringUtils.isBlank(cmd) || value==null){
			return false;
		}
		Map<String,Object> bodyMap = new HashMap<String, Object>();
		bodyMap.put(idColumn, value);
		return sendClearCmd4Boolean(cmd, bodyMap);
	}

	public static String sendMessage4StringCache(String cmd, String serviceName, Map<String,Object> bodyMap)throws Exception{
		String message = null;
		try {
			message = getMessage(cmd, serviceName, bodyMap);
		} catch (UnsupportedEncodingException e1) {
			e1.printStackTrace();
		}
		MessageSt messageSt = new MessageSt();
		try {
			sendReceiveMessage(message, messageSt);
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return parseMsgBodyStringCache(messageSt);
	}

	private static String parseMsgBodyStringCache(MessageSt messageSt)throws SocketException{
		if(messageSt != null){
			System.out.println("*****parseMsgBodyString:"+JSON.toJSONString(messageSt, false));
			String bodyMsg = messageSt.getBodyContent();
			System.out.println(bodyMsg);
			if(StringUtils.isNotEmpty(bodyMsg)){
				JSONObject bodyObj = JSON.parseObject(bodyMsg);
				String resFlag = bodyObj.getString("result");
				if(StringUtils.isNotBlank(resFlag)){
					if(resFlag.equals("ok")){
						return bodyObj.getString("result_data");
					}else if(resFlag.equals("error") || resFlag.equals("timeout")){
						throw new SocketException("result error:"+bodyObj.getString("result_data"));
					}
				}
			}
		}
		return "";
	}
	
	public static void main(String args[])throws Exception{
		Map<String,Object> bodyMap = new HashMap<String, Object>();
		//bodyMap.put("barId", 144186);
		//boolean flag = false;
//		flag = MiddlewareUtil.sendMessage4Boolean("GetBarByInternetBarId", "APP_0013", bodyMap);
//		System.out.println(flag);
//		
//		flag = MiddlewareUtil.sendMessage4Boolean("ClearBarByInternetBarId", "APP_0013", bodyMap);
//		System.out.println(flag);
		
		String json = null;
//		bodyMap.clear();
//		bodyMap.put("snbid", "jswx-196");
//		bodyMap.put("currentTime", System.currentTimeMillis()/1000);
//		json = MiddlewareUtil.sendMessage4String("GetBarEffectiveCouponInfo", "APP_0013", bodyMap);
//		System.out.println(json);
//		
//		flag = MiddlewareUtil.sendMessage4Boolean("ClearBarEffectiveCouponInfo", "APP_0013", bodyMap);
//		System.out.println(flag);
		
		
//		bodyMap.clear();
//		bodyMap.put("snbid", "jswx-196");
//		bodyMap.put("currentTime", System.currentTimeMillis()/1000);
//		json = MiddlewareUtil.sendMessage4String("GetBarCouponBag", "APP_0013", bodyMap);
//		System.out.println(json);
//		
//		flag = MiddlewareUtil.sendMessage4Boolean("ClearBarCouponBag", "APP_0013", bodyMap);
//		System.out.println(flag);
		
//		bodyMap.clear();
//		bodyMap.put("snbid", "jswx-196");
//		bodyMap.put("barId", 144186);
//		bodyMap.put("futureTime", 1468939646);
//		bodyMap.put("currentTime", 1438948458);
//		json = MiddlewareUtil.sendMessage4String("GetBarWelFareActivity", "APP_0013", bodyMap);
//		System.out.println(json);
//		
//		flag = MiddlewareUtil.sendMessage4Boolean("ClearBarWelFareActivity", "APP_0013", bodyMap);
//		System.out.println(flag);
		
		
//		bodyMap.clear();
//		bodyMap.put("snbid", "jswx-196");
//		bodyMap.put("barId", 144186);
//		bodyMap.put("futureTime", 1468939646);
//		bodyMap.put("welfareActivitiesId", 58);
//		json = MiddlewareUtil.sendMessage4String("GetPrizeInfo", "APP_0013", bodyMap);
//		System.out.println(json);
//		
//		flag = MiddlewareUtil.sendMessage4Boolean("ClearPrizeInfo", "APP_0013", bodyMap);
//		System.out.println(flag);
//		
		
//		bodyMap.clear();
//		bodyMap.put("snbid", "jswx-196");
//		bodyMap.put("barId", 144186);
//		bodyMap.put("futureTime", 1468939646);
//		bodyMap.put("welfareActivitiesId", 58);
//		json = MiddlewareUtil.sendMessage4String("GetBarHotActivity", "APP_0013", bodyMap);
//		System.out.println(json);
//		
//		flag = MiddlewareUtil.sendMessage4Boolean("ClearBarHotActivity", "APP_0013", bodyMap);
//		System.out.println(flag);
		
		
		
		/*bodyMap.clear();
		bodyMap.put("snbid", "jswx-196");
		bodyMap.put("barId", 144186);
		bodyMap.put("futureTime", 1468939646);
		bodyMap.put("welfareActivitiesId", 58);
		json = MiddlewareUtil.sendMessage4String("GetBarService", "APP_0013", bodyMap);
		System.out.println(json);
		
		flag = MiddlewareUtil.sendMessage4Boolean("ClearBarService", "APP_0013", bodyMap);
		System.out.println(flag);*/

		//根据网吧帐号查询开启段位语音
		/*bodyMap.clear();
		bodyMap.put("snbid", "pt2_1");
		json = MiddlewareUtil.sendMessage4String("GetOpenVoiceInfoBySnbid", "LOL_VOICE_INFO", bodyMap);
		if(StringUtils.isNotBlank(json)){
			JSONArray bodyObj = JSON.parseArray(json);
			System.out.println(bodyObj.getJSONObject(0));
		}else {
			System.out.println(json);
		}*/


		/*//清理网吧帐号查询开启段位语音缓存
		bodyMap.clear();
		bodyMap.put("snbid", "jswx-196");
		Boolean aBoolean = MiddlewareUtil.sendMessage4Boolean("ClearOpenVoiceInfoBySnbid", "LOL_VOICE_INFO", bodyMap);
		System.out.println(aBoolean);*/

		//查询网吧是否是VIP
		/*bodyMap.clear();
		bodyMap.put("snbid", "pt2_1");
		bodyMap.put("businessType", "1");
		bodyMap.put("expire", "43200");
		Boolean aBoolean = MiddlewareUtil.sendMessage4Boolean("GetIsVipBar", "LOL_BAR_VIP", bodyMap);
		System.out.println(aBoolean);*/

		//网吧注册VIP时，更新到缓存
		/*bodyMap.clear();
		bodyMap.put("snbid", "pt2_1");
		bodyMap.put("businessType", "1");
		Boolean aBoolean = MiddlewareUtil.sendMessage4Boolean("ClearIsVipBar", "LOL_BAR_VIP", bodyMap);
		System.out.println(aBoolean);*/


		//根据网吧帐号获取默认角色信息(userId分表)
		/*bodyMap.clear();
		bodyMap.put("roleId", "1");
		bodyMap.put("userId", "81");
		json = MiddlewareUtil.sendMessage4String("GetDefaultRoleInfo", "LOL_ROLEINFO", bodyMap);
		System.out.println(json);*/


		//根据网吧帐号获取默认角色ID(snbid分表)
		/*bodyMap.clear();
		bodyMap.put("snbid", "jswx-196");
		bodyMap.put("userId", "34059670");//可以查e0表有测试数据
		json = MiddlewareUtil.sendMessage4String("GetDefaultRoleId", "LOL_ROLEID", bodyMap);
		System.out.println(json);*/

		//只查询内存
		/*bodyMap.clear();
		bodyMap.put("snbid", "jswx-196");
		bodyMap.put("userId", "34059670");//可以查e0表有测试数据
		json = MiddlewareUtil.sendMessage4StringCache("GetDefaultRoleIdCache", "LOL_ROLEID", bodyMap);
		if(StringUtils.isNotBlank(json)){
			JSONArray bodyObj = JSON.parseArray(json);
			System.out.println(bodyObj.getJSONObject(0).getIntValue("game_role_id"));
		}else {
			System.out.println(json);
		}*/

		/*{"result":"ok","result_data":[{"game_role_id":15}],"row_count":1}*/
		/*JSONObject jsonObject = new JSONObject();
		JSONObject roleIdObject = new JSONObject();
		roleIdObject.put("game_role_id",18);
		JSONArray jsonArray = new JSONArray();
		jsonArray.add(0,roleIdObject);
		jsonObject.put("result","ok");
		jsonObject.put("result_data",jsonArray);
		jsonObject.put("row_count",1);
		bodyMap.clear();
		bodyMap.put("snbid", "jswx-196");
		bodyMap.put("userId", "34059670");//可以查e0表有测试数据
		bodyMap.put("dataStr", JSON.toJSONString(jsonObject));
		json = MiddlewareUtil.sendMessage4StringCache("UpdateDefaultRoleIdCache", "LOL_ROLEID", bodyMap);
		if(StringUtils.isNotBlank(json)){
			JSONArray bodyObj = JSON.parseArray(json);
			System.out.println(bodyObj.getJSONObject(0).getIntValue("game_role_id"));
		}else {
			System.out.println(json);
		}*/

		/*bodyMap.put("snbid","pt2_1");
		JSONArray internetBarVersionArr = MiddlewareUtil.sendMessage4Array(MiddleWareCMD.GETBARVERSIONBYSNBID, MiddleWareServiceName.INDEX_LOGIN, bodyMap);*/

		/*bodyMap.clear();
		bodyMap.put("snbid", "jswx-196");
		bodyMap.put("barId", "144186");
		bodyMap.put("vendor_type","01");
		Boolean aBoolean = MiddlewareUtil.sendMessage4Boolean("GetInternetBar", "APP_0013", bodyMap);
		System.out.println(aBoolean);*/

		/*bodyMap.clear();
		bodyMap.put("snbid", "jswx-196");
		bodyMap.put("barId", "144186");
		bodyMap.put("vendor_type","01");
		Boolean aBoolean = MiddlewareUtil.sendMessage4Boolean(MiddleWareCMD.CLEAR_BAR_INFO, "APP_0013", bodyMap);
		Boolean bBoolean = MiddlewareUtil.sendMessage4Boolean(MiddleWareCMD.CLEAR_BAR_INFO_BY_SNBID, "INTENET_BAR", bodyMap);
		System.out.println(aBoolean + " ========== " + bBoolean);*/
	}
}